package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author 林云
 * @since 2023-08-08
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    final CourseClient courseClient;

    final CatalogueClient catalogueClient;

    final LearningRecordMapper recordMapper;

    /**
     * 保存课表
     */
    @Override
    public void addUserLesson(Long userId, List<Long> courseIds) {

        //远程调用course服务，获取课程基础信息
        List<CourseSimpleInfoDTO> clist = courseClient.getSimpleInfoList(courseIds);
        //批量赋值给po
        List<LearningLesson> lessons = new ArrayList<>();
        for (CourseSimpleInfoDTO course : clist) {
            LearningLesson lesson = new LearningLesson();
            lesson.setUserId(userId);
            lesson.setCourseId(course.getId());
            Integer validDuration = course.getValidDuration();
            //判断是不是永久有效
            if (validDuration != null) {
                LocalDateTime now = LocalDateTime.now();
                //重新设置，更加精确
                lesson.setCreateTime(now);
                //validDuration以月为单位
                lesson.setExpireTime(now.plusMonths(validDuration));
                lessons.add(lesson);
            }
        }
        //批量保存
        this.saveBatch(lessons);

    }

    /**
     * 分页查询我的课表
     */
    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery pageQuery) {
        //1.获取用户id
        Long userId = UserContext.getUser();

        //2.查询用户有哪些课程
        Page<LearningLesson> pageInfo = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> lessonList = pageInfo.getRecords();
        if (CollUtils.isEmpty(lessonList)) {
            return PageDTO.empty(pageInfo);
        }
        //提取courseId为集合
        List<Long> courseIds = lessonList.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());

        //3.远程调用获取课程信息
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(courseList)) {
            throw new BizIllegalException("课程不存在");
        }
        //提取id:course
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        //4.转换成vo
        List<LearningLessonVO> voList = new ArrayList<>();
        for (LearningLesson lesson : lessonList) {
            CourseSimpleInfoDTO courseDto = courseMap.get(lesson.getCourseId());
            LearningLessonVO lessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
            if (courseDto != null) {
                lessonVO.setCourseCoverUrl(courseDto.getCoverUrl());
                lessonVO.setCourseName(courseDto.getName());
                lessonVO.setSections(courseDto.getSectionNum());
            }
            voList.add(lessonVO);
        }
        //5.返回
        return PageDTO.of(pageInfo, voList);
    }

    /**
     * 查询最近一次学习的课程
     */
    @Override
    public LearningLessonVO queryMyCurrentLesson() {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.查询最近的一次课程
        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .orderByDesc(LearningLesson::getLatestLearnTime)
                .last("limit 1")
                .one();
        if (lesson == null) {
            return null;
        }
        //3.远程调用课程服务
        CourseFullInfoDTO courseDto = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
        if (courseDto == null) {
            throw new BizIllegalException("课程不存在");
        }
        //4.查询课表中已报名的总课程数
        Integer count = this.lambdaQuery().eq(LearningLesson::getUserId, userId).count();
        //5.查询小节相关
        Long latestSectionId = lesson.getLatestSectionId();
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(CollUtils.toList(latestSectionId));
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new BizIllegalException("小节不存在");
        }
        //构造vo
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        vo.setCourseName(courseDto.getName());
        vo.setCourseCoverUrl(courseDto.getCoverUrl());
        vo.setSections(courseDto.getSectionNum());
        vo.setCourseAmount(count);//课程总数
        vo.setLatestSectionIndex(cataSimpleInfoDTOS.get(0).getCIndex());//最近学习小节的序号
        vo.setLatestSectionName(cataSimpleInfoDTOS.get(0).getName());//最近学习小节的名称
        return vo;
    }

    /**
     * 删除课表中的课程
     */
    @Override
    public void deleteLessonByCId(Long courseId) {
        //获取用户id
        Long userId = UserContext.getUser();
        //查询课程
        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null) {
            throw new BizIllegalException("课程不存在");
        }
        //判断是否过期
        LocalDateTime expireTime = lesson.getExpireTime();
        LocalDateTime now = LocalDateTime.now();
        if (expireTime.isAfter(now)) {
            throw new BizIllegalException("课程有效无法删除");
        }
        //删除
        this.lambdaUpdate().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).remove();
    }

    /**
     * 校验课程有效性
     */
    @Override
    public Long isLessonValid(Long courseId) {
        //获取用户id
        Long userId = UserContext.getUser();
        //查询课程是否存在
        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null) {
            return null;
        }
        //检验课程有效性
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = lesson.getExpireTime();
        if (expireTime != null && now.isAfter(expireTime)) {
            return null;
        }
        //返回lesson_id
        return lesson.getId();
    }

    /**
     * 查询指定课表状态
     */
    @Override
    public LearningLessonVO queryLessonByCourseId(Long courseId) {
        log.info("查询指定课表状态----courseId:{}", courseId);
        Long userId = UserContext.getUser();
        //查询课程是否存在
        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId).one();
        if (lesson == null) {
            throw new BizIllegalException("课程不存在");
        }
        LearningLessonVO learningLessonVO = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        return learningLessonVO;
    }

    /**
     * 统计课程学习人数
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        return this.lambdaQuery().eq(LearningLesson::getCourseId, courseId).count();
    }

    /**
     * 创建学习计划
     */
    @Override
    public void createLearningPlans(LearningPlanDTO dto) {
        // 1.获取当前登录用户的id
        Long userId = UserContext.getUser();
        // 2.查询课表
        LearningLesson lesson = this.lambdaQuery().eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, dto.getCourseId())
                .one();
        if (lesson == null) {
            throw new BizIllegalException("课程未加入课表");
        }
        // 3.更新频率和计划状态
        this.lambdaUpdate().set(LearningLesson::getWeekFreq, dto.getFreq())
                .set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .eq(LearningLesson::getId, lesson.getId())// 根据主键更新
                .update();
    }

    /**
     * 查询学习计划
     */
    public LearningPlanPageVO queryMyPlans(PageQuery pageQuery) {
        // 1.获取当前登录用户的id
        Long userId = UserContext.getUser();
        // todo 2.查询积分
        // 3.查询计划总数量
        QueryWrapper<LearningLesson> wrapper = new QueryWrapper<>();
        wrapper.select("sum(week_freq) as plansTotal");
        wrapper.eq("user_id", userId);
        wrapper.eq("plan_status", PlanStatus.PLAN_RUNNING);
        wrapper.in("status", LessonStatus.NOT_BEGIN, LessonStatus.LEARNING);
        Map<String, Object> map = this.getMap(wrapper);
        Integer plansTotal = 0;
        if (map != null && map.get("plansTotal") != null) {
            plansTotal = Integer.valueOf(map.get("plansTotal").toString());
        }
        // 4.查询本周已经学了多少节(数量)
        LocalDate now = LocalDate.now();
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(now);
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(now);
        Integer weekFinishedPlanSum = recordMapper.selectCount(Wrappers.<LearningRecord>lambdaQuery()
                .eq(LearningRecord::getUserId, userId)
                .eq(LearningRecord::getFinished, true)
                .between(LearningRecord::getFinishTime, weekBeginTime, weekEndTime));
        // 5.分页查询 按最近学习时间倒序
        Page<LearningLesson> page = this.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));
        List<LearningLesson> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            LearningPlanPageVO vo = new LearningPlanPageVO();
            vo.setTotal(0L);
            vo.setPages(0L);
            vo.setList(CollUtils.emptyList());
            return vo;
        }
        // 6.远程调用课程微服务，获取课程信息，用于填充缺失属性
        // 6.1.提取所有courseId
        List<Long> cIdList = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIdList);
        if (CollUtils.isEmpty(cInfoList)) {
            throw new BizIllegalException("课程不存在");
        }
        // 6.2.整为map，无需双重循环
        Map<Long, CourseSimpleInfoDTO> cInfoMap = cInfoList.stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
        // 7.查询不同课表在本周的完成章节数
        QueryWrapper<LearningRecord> recordQueryWrapper = new QueryWrapper<>();
        recordQueryWrapper.select("lesson_id as lessonId", "count(*) as userId"); //userId不是真的userId，只是暂时存储用
        recordQueryWrapper.eq("user_id", userId);
        recordQueryWrapper.eq("finished", true);
        recordQueryWrapper.between("finish_time", weekBeginTime, weekEndTime);
        recordQueryWrapper.groupBy("lesson_id");
        List<LearningRecord> recordList = recordMapper.selectList(recordQueryWrapper);
        // 7.1.提取为map，lesson_id -> userId(暂存，并非真的userId，实际上是count)
        Map<Long, Long> courseWeekSumMap = recordList.stream().collect(Collectors.toMap(LearningRecord::getLessonId, c -> c.getUserId()));
        // 8.封装成vo返回
        LearningPlanPageVO vo = new LearningPlanPageVO();
        vo.setWeekTotalPlan(plansTotal);
        vo.setWeekFinished(weekFinishedPlanSum);
        List<LearningPlanVO> list = new ArrayList<>();
        for (LearningLesson record : records) {
            LearningPlanVO planVO = BeanUtils.copyBean(record, LearningPlanVO.class);
            CourseSimpleInfoDTO courseDto = cInfoMap.get(record.getCourseId());
            if (courseDto != null) {
                //补充两个缺失属性
                planVO.setCourseName(courseDto.getName());//课程名称
                planVO.setSections(courseDto.getSectionNum());//总小节
            }
            // 本周已学习章节数 使用getOrDefault方法，如果获取不到默认就是0
            planVO.setWeekLearnedSections(courseWeekSumMap.getOrDefault(record.getId(), 0L).intValue());
            list.add(planVO);
        }

        return vo.pageInfo(page.getTotal(), page.getPages(), list);
    }


}
